# 怎么获取有哪些参数，权重，配置可以调整呢？
#
# 在PyTorch中，获取模型的参数、权重和配置可以通过以下几种方式：
#
# 获取模型的所有参数
#
# 使用model.parameters()
# 方法可以获取网络的所有权重参数。例如：
#
# import torch
# import torch.nn as nn
# class SimpleModel(nn.Module):
#     def __init__(self):
#         super(SimpleModel, self).__init__()
#         self.fc1 = nn.Linear(10, 20)
#         self.fc2 = nn.Linear(20, 1)
#
#     def forward(self, x):
#         x = self.fc1(x)
#         x = self.fc2(x)
#         return x
#
#
# model = SimpleModel()
# params = list(model.parameters())
# for p in params:
#     print(p)
#
# model.state_dict()
# 方法也可以获取到模型的所有参数字典，它包含了模型的所有层及其相应的权重和偏置。例如：
# state_dict = model.state_dict()
#
# 获取每一层权重参数
#
# 遍历模型的所有模块，并对每个模块调用.parameters()
# 方法。例如：
# for name, module in model.named_modules():
#     if isinstance(module, nn.Linear):  # 这里假设我们只关心全连接层，可以根据需要调整条件
#         params = list(module.parameters())
#         print(f"Layer {name}:")
#         for p in params:
#             print(p)
#
# 通过model.named_parameters()
# 方法可以获取模型中所有参数的名称和值，然后根据名称筛选出每层的权重参数。例如：
# for name, param in model.named_parameters():
#     if 'weight' in name:
#         print(f"{name}: {param.shape}")
#
# 获取模型的配置
#
# 模型的配置通常指的是模型的架构信息，如网络的层数、每层的类型、输入输出的维度等。这些信息可以通过查看模型的定义代码来获取，也可以通过一些第三方库来辅助查看。例如，可以使用torchsummary库来查看模型的架构摘要：
# from torchsummary import summary
#
# summary(model, input_size=(input_shape), device='cpu')
#
# 对于一些常见的模型架构，如ResNet、VGG等，可以直接查看其定义代码或官方文档来了解其配置。例如，ResNet通常包含多个卷积层、批归一化层和残差块等。
# 综上所述，在PyTorch中获取模型的参数、权重和配置有多种方法，开发者可以根据自己的需求选择合适的方法进行操作。
#
# ## 如何调整模型的参数？
# 在PyTorch中，调整模型的参数可以通过多种方式实现，包括直接修改权重和偏置、使用优化器进行训练等。以下是一些常见的方法：
#
# 1.
# 直接修改权重和偏置
# 你可以直接访问模型的参数并手动修改它们。例如：
#
#
# python
# 复制代码
# import torch
# import torch.nn as nn
#
#
# class SimpleModel(nn.Module):
#     def __init__(self):
#         super(SimpleModel, self).__init__()
#         self.fc1 = nn.Linear(10, 20)
#         self.fc2 = nn.Linear(20, 1)
#
#     def forward(self, x):
#         x = self.fc1(x)
#         x = self.fc2(x)
#         return x
#
#
# model = SimpleModel()
#
# # 打印原始权重
# print("Original weights of fc1:", model.fc1.weight)
#
# # 修改权重
# with torch.no_grad():
#     model.fc1.weight += 0.1
#
# # 打印修改后的权重
# print("Modified weights of fc1:", model.fc1.weight)
#
# 2.
# 使用优化器进行训练
# 通常，我们通过定义损失函数和优化器来训练模型，从而自动调整模型的参数。以下是一个示例：
#
#
# python
# 复制代码
# import torch
# import torch.nn as nn
# import torch.optim as optim
#
#
# class SimpleModel(nn.Module):
#     def __init__(self):
#         super(SimpleModel, self).__init__()
#         self.fc1 = nn.Linear(10, 20)
#         self.fc2 = nn.Linear(20, 1)
#
#     def forward(self, x):
#         x = self.fc1(x)
#         x = self.fc2(x)
#         return x
#
#
# model = SimpleModel()
# criterion = nn.MSELoss()
# optimizer = optim.SGD(model.parameters(), lr=0.01)
#
# # 假设我们有输入数据和目标数据
# inputs = torch.randn(5, 10)
# targets = torch.randn(5, 1)
#
# # 前向传播
# outputs = model(inputs)
# loss = criterion(outputs, targets)
#
# # 反向传播和优化
# optimizer.zero_grad()
# loss.backward()
# optimizer.step()
#
# 3.
# 冻结部分参数
# 有时你可能希望冻结某些层的参数，使其在训练过程中保持不变。这可以通过设置requires_grad属性来实现：
#
#
# python
# 复制代码
# for param in model.fc1.parameters():
#     param.requires_grad = False
#
# 4.
# 加载预训练模型并微调
# 你可以加载一个预训练模型，然后只训练最后几层或特定层的参数：
#
#
# python
# 复制代码
# from torchvision import models
#
# # 加载预训练的ResNet模型
# model = models.resnet18(pretrained=True)
#
# # 冻结所有层的参数
# for param in model.parameters():
#     param.requires_grad = False
#
# # 替换最后的全连接层以适应新的任务
# num_ftrs = model.fc.in_features
# model.fc = nn.Linear(num_ftrs, num_classes)
#
# # 仅训练新添加的层
# optimizer = optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9)
#
# 5.
# 使用学习率调度器调整学习率
# 学习率调度器可以帮助你在训练过程中动态调整学习率，从而更好地优化模型：
#
#
# python
# 复制代码
# scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
# for epoch in range(num_epochs):
#     train(...)
#     validate(...)
#     scheduler.step()
#
# 通过这些方法，你可以灵活地调整模型的参数，以获得更好的性能。
#
# ## 如何调整模型的权重参数
# 在PyTorch中，调整模型的权重参数通常通过以下几种方式实现：
#
# 1.
# 直接修改权重和偏置
# 你可以直接访问模型的参数并手动修改它们。例如：
#
#
# python
# 复制代码
# import torch
# import torch.nn as nn
#
#
# class SimpleModel(nn.Module):
#     def __init__(self):
#         super(SimpleModel, self).__init__()
#         self.fc1 = nn.Linear(10, 20)
#         self.fc2 = nn.Linear(20, 1)
#
#     def forward(self, x):
#         x = self.fc1(x)
#         x = self.fc2(x)
#         return x
#
#
# model = SimpleModel()
#
# # 打印原始权重
# print("Original weights of fc1:", model.fc1.weight)
#
# # 修改权重
# with torch.no_grad():
#     model.fc1.weight += 0.1
#
# # 打印修改后的权重
# print("Modified weights of fc1:", model.fc1.weight)
#
# 2.
# 使用优化器进行训练
# 通常，我们通过定义损失函数和优化器来训练模型，从而自动调整模型的参数。以下是一个示例：
#
#
# python
# 复制代码
# import torch
# import torch.nn as nn
# import torch.optim as optim
#
#
# class SimpleModel(nn.Module):
#     def __init__(self):
#         super(SimpleModel, self).__init__()
#         self.fc1 = nn.Linear(10, 20)
#         self.fc2 = nn.Linear(20, 1)
#
#     def forward(self, x):
#         x = self.fc1(x)
#         x = self.fc2(x)
#         return x
#
#
# model = SimpleModel()
# criterion = nn.MSELoss()
# optimizer = optim.SGD(model.parameters(), lr=0.01)
#
# # 假设我们有输入数据和目标数据
# inputs = torch.randn(5, 10)
# targets = torch.randn(5, 1)
#
# # 前向传播
# outputs = model(inputs)
# loss = criterion(outputs, targets)
#
# # 反向传播和优化
# optimizer.zero_grad()
# loss.backward()
# optimizer.step()
#
# 3.
# 冻结部分参数
# 有时你可能希望冻结某些层的参数，使其在训练过程中保持不变。这可以通过设置requires_grad属性来实现：
#
#
# python
# 复制代码
# for param in model.fc1.parameters():
#     param.requires_grad = False
#
# 4.
# 加载预训练模型并微调
# 你可以加载一个预训练模型，然后只训练最后几层或特定层的参数：
#
#
# python
# 复制代码
# from torchvision import models
#
# # 加载预训练的ResNet模型
# model = models.resnet18(pretrained=True)
#
# # 冻结所有层的参数
# for param in model.parameters():
#     param.requires_grad = False
#
# # 替换最后的全连接层以适应新的任务
# num_ftrs = model.fc.in_features
# model.fc = nn.Linear(num_ftrs, num_classes)
#
# # 仅训练新添加的层
# optimizer = optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9)
#
# 5.
# 使用学习率调度器调整学习率
# 学习率调度器可以帮助你在训练过程中动态调整学习率，从而更好地优化模型：
#
#
# python
# 复制代码
# scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
# for epoch in range(num_epochs):
#     train(...)
#     validate(...)
#     scheduler.step()
#
# 6.
# 自定义权重初始化方法
# 你也可以自定义权重初始化方法，以确保模型在训练开始时具有合理的初始值：
#
#
# python
# 复制代码
#
#
# def init_weights(m):
#     if isinstance(m, nn.Linear):
#         torch.nn.init.xavier_uniform_(m.weight)
#         m.bias.data.fill_(0.01)
#
#
# model.apply(init_weights)
#
# 通过这些方法，你可以灵活地调整模型的权重参数，以获得更好的性能。


